做一個 Todolist,按右上角按鈕會跳到第二個頁面,有一個 EditText 可輸入待辦事項,確認點選後會跳回原先的頁面,此時第一頁會多出一行剛剛新增的事項。
使用:Activity 切換、RecycleView、Adapter、Menu等
這些使用到的元件多半是之前寫過的功能,語法和 layout 的部分會略過,來練習看著上面這張 gif 圖把他們寫出來(會備註在哪個 .kt 檔):
單純切換的功能,只要設定跳轉到下一個頁面就好,不過因為等下會讀取夾帶回來的資料,所以在 Menu Item 要設定可以返回--- startActivityForResult
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu, menu)
return super.onCreateOptionsMenu(menu)
} //menuInflater
override fun onOptionsItemSelected(item: MenuItem): Boolean {
item.itemId == R.id.menu_add
startActivityForResult(Intent(this, Main2Activity::class.java),1)
return super.onOptionsItemSelected(item)
} //MenuItem
從第一頁跳過來之後,會有一個 EditText 要輸入、兩個按鈕分別為確認 (check) 及取消鍵 (cancel),這邊要注意:
(1) 確認鍵
editText2.text.isBlank()
Bundle.putString
及 Intent.putExtras
btn_check.setOnClickListener {
if (editText2.text.isBlank())
Toast.makeText(this, "請輸入待辦事項", Toast.LENGTH_SHORT).show()
else {
val b = Bundle()
b.putString("todo", "${editText2.text}")
val intent1 = Intent()
intent1.putExtras(b)
setResult(Activity.RESULT_OK, intent1)
finish()
Toast.makeText(this, "${editText2.text}儲存成功", Toast.LENGTH_SHORT).show()
}
}
(2) 取消返回鍵
之前沒有注意 finish() 用法,查了一下才知道 startActivityForResult 和 startActivity 其中一個差異在於跳轉頁面的返回,如果用後者要跳轉回去只能再使用一次 startActivity()?
startActivityForResult 則不同,它可以調用 finish() 這個用法來一次性完成,也只有寫這行時 Activity 才會返回,看上面程式碼就會發現 setResult() 被寫在 finish() 前面!所以
setResult()
是用來回傳數據,不會馬上返回Back
事件btn_cancel.setOnClickListener {
finish() //取消鍵就調用 finish() 方法
}
主頁 RecycleView 清單是用來顯示回傳資料的,而 RecycleView 在之前 Day 8 ─用Kotlin RecycleView做一個ImageList 講過,繼續來練習它、熟悉它,這次顯示的資料內容比較簡單,只有一行字串(上次是圖片+文字):
Step 1. 定義資料
在 Adpater.kt 定義 Thing 為 String
型態的資料
data class Thing(val todo: String)
Step 2. 繼承 Adpater
class 繼承 RecyclerView.Adapter<>,添加一個泛型 <ViewHolder>
,讓其繼承 RecyclerView.ViewHolder,裡面定義等下會使用到的元件和函式(inner class)
class MyAdapter(private val things:ArrayList<Thing>) :
RecyclerView.Adapter<MyAdapter.ViewHolder>(){
inner class ViewHolder(v: View):RecyclerView.ViewHolder(v){
val tv_todo = v.findViewById<TextView>(R.id.tv_todo)
fun bind(todo: String){
tv_todo.setText(todo)
} //等下會在onBindViewHolder方法執行它
}
}
綁定 itemView 裡面的 TextView(findViewById
)
Step 3. 完成 Adapter 待執行的三個方法
onCreateViewHolder()
inflate(resource: Int, root: ViewGroup?, attachToRoot: Boolean): View!
getItemCount()
onBindViewHolder()
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.activity_my_adapter, viewGroup, false)
return ViewHolder(view)
}
override fun getItemCount() = things.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(things[position].todo)
//把 function bind 指給 holder
Step 4. 呈現 RecycleView(MainActivity.kt)
先定義 adapter 和things,等下讀取返回資料時要用到
private lateinit var adapter : MyAdapter
private var things = ArrayList<Thing>()
把 adapter 和 layoutManager 指給 RecycleView來呈現
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
adapter = MyAdapter(things)
recycleview.layoutManager = LinearLayoutManager(this)
recycleview.adapter = adapter
}
在 2. 就把資料夾帶跳轉回主頁,主頁的 RecycleView也做好,剩下最後一步驟是接收並讀取在bundle裡面的字串,不清楚流程的可以去 Day 4 ─用Kotlin做點餐介面 (2) intent 複習記憶:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// requestCode 和 resultCode
if (requestCode == 1 && resultCode == Activity.RESULT_OK) {
val todo = data?.extras?.getString("todo")
things.add(Thing(todo!!))
// 必須調用這個方法才能刷新清單內容
adapter.notifyDataSetChanged()
}
}
今天整合很多之前練習的東西,包括 Menu、 RecycleView 和 Activity 夾帶資料的用法,是一個很實用的題目,明天會針對 Todolist 添加更多功能!